package rip.core;

import com.mongodb.DB;
import com.mongodb.Mongo;
import com.mongodb.MongoURI;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import javax.servlet.ServletConfig;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Properties;

public class RIPServlet extends HttpServlet {
    private String applicationPackage;
    private String persistenceUnit;
    private EntityManagerFactory emf;
    private static EntityManagerFactory testEmf;
    private DB db;
    private boolean testMode = false;
    private Properties envProperties = null;

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        applicationPackage = "fi.bluepill.server.rest";

        if (System.getProperty("LOCAL_TESTING") != null)
            testMode = true;

        envProperties = new Properties();
        try {
            envProperties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("environment.properties"));
        } catch (IOException e) {
            throw new IllegalStateException("Could not load environment properties", e);
        }

        persistenceUnit = envProperties.getProperty("jpa.persistence.unit");
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doService(request, response);
    }

    public  void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doService(request, response);
    }

    private void doService(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if (request.getPathInfo().equals("/favicon.ico")) {
            response.setStatus(404);
            return;
        }

        RIPService service = (RIPService) loadServiceObject(serviceObjectName(request));
        service.setRequest(request);
        service.setResponse(response);
        service.setEmf(getEMF());
        service.setDb(getDb());
        service.setTestMode(testMode);
        service.setEnvProperties(envProperties);
        service.execute(serviceMethodName(request));
    }

    private String serviceObjectName(HttpServletRequest request) {
        String[] pathSplit = request.getPathInfo().split("\\/");
        String[] nameSplit = pathSplit[1].split("_");

        String name = "";

        for (int i = 0; i < nameSplit.length; i++) {
            String s = nameSplit[i];

            name += Character.toUpperCase(s.charAt(0)) + s.substring(1, s.length());
        }

        return name + "Service";
    }

    private String serviceMethodName(HttpServletRequest request) {
        String[] pathSplit = request.getPathInfo().split("\\/");

        String methodName = null;

        if (pathSplit.length > 2) {
            methodName = "";

            for (int i = 2; i < pathSplit.length; i++) {
                methodName += pathSplit[i];

                if (i < pathSplit.length-1)
                    methodName += "_";
            }
        }

        return methodName;
    }

    private EntityManagerFactory getEMF() {
        if (testEmf != null)
            return testEmf;

        if (emf == null) {
            String dbString = System.getenv("CLEARDB_DATABASE_URL");

            if (dbString == null)
                dbString = System.getProperty("JDBC_CONNECTION_STRING");

            if (dbString == null)
                dbString = System.getProperty("CLEARDB_DATABASE_URL");

            URI dbUri = null;
            try {
                dbUri = new URI(dbString);
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
            Properties emfProperties = new Properties();

            if (dbUri.getUserInfo() != null)
                emfProperties.put("javax.persistence.jdbc.user", dbUri.getUserInfo().split(":")[0]);

            if (dbUri.getUserInfo() != null)
                emfProperties.put("javax.persistence.jdbc.password", dbUri.getUserInfo().split(":")[1]);

            StringBuilder sb = new StringBuilder("jdbc:");

            sb.append(dbUri.getScheme());

            if (dbUri.getHost() != null)
                sb.append("://").append(dbUri.getHost());
            else
                sb.append(":");

            if (dbUri.getPath() != null)
                sb.append(dbUri.getPath());

            if (testMode && dbUri.getSchemeSpecificPart() != null)
                sb.append(dbUri.getSchemeSpecificPart());


            emfProperties.put("javax.persistence.jdbc.url", sb.toString());
            emf = Persistence.createEntityManagerFactory(persistenceUnit, emfProperties);
        }

        return emf;
    }

    private DB getDb() {
        if (db == null) {
            Mongo mongo = null;
            String dbString = System.getenv("MONGOLAB_URI");

            if (dbString == null)
                dbString = System.getProperty("PARAM1");

            if (dbString == null)
                dbString = System.getProperty("MONGOLAB_URI");


            try {
                mongo = new Mongo(new MongoURI(dbString));
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }

            URI mongolabUri = null;
            try {
                mongolabUri = new URI(dbString);
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }

            String dbName = mongolabUri.getPath().replaceAll("/", "");

            if (!testMode && mongolabUri.getUserInfo() != null) {
                db = mongo.getDB(dbName);
                db.authenticate(mongolabUri.getUserInfo().split(":")[0], mongolabUri.getUserInfo().split(":")[1].toCharArray());
            }
            else
                db = mongo.getDB(envProperties.getProperty("mongo.database"));
        }

        return db;
    }

    private Object loadServiceObject(String name) {
        try {
            Class c = Thread.currentThread().getContextClassLoader().loadClass(applicationPackage + "." + name);
            return c.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static void setTestEmf(EntityManagerFactory emf) {
        testEmf = emf;
    }

}
